Crazy Sub

by Fredrik Ramsberg

A game in C64 Basic V2, and an entry into the 2020 Basic 10-liners competition.

Instructions:

Load and start the game into Vice or on a real C64:

load "*",8
run

Controls: Any key to fire a torpedo.

You are the commander of a submarine, trying to hit an enemy ship with all of your torpedoes. 
While you can never hope to sink the enemy ship, you must try to weaken it as much as possible 
so others can land the final blow. You have nine torpedoes. As it turns out, someone has tried
to sabotage your mission by supplying you with a mix of torpedoes with different power ratings.
The higher the power rating (0-9), the faster the torpedo will reach the enemy ship.

The battle screen shows how many torpedoes you have left (TP), the power rating of the currently
loaded torpedo (PW) and your score (SC). Do you have what it takes to get a perfect score of 
900 points?

After firing all nine torpedoes, the program ends and your final score is displayed. Type "run" 
to play again.



Program explanation:

0 
	k=54273 								; Set k to the first address we want to initalize in SID chip
	dimy%,a%(500)							; Declare y% now, since it would otherwise movea a%() the first
											;	time it's used. Declare a%(500) to set 1000 addresses to 0,
											; 	to clear contents of memory where sprites will reside
	for i=0 to 5							; Loop to read six lines of data each for two sprites
		ifi<3then							; While we loop, initialize all three voices of SID 
			poke k,60						; Set frequency
			poke k+4,10						; Set attack and decay
			poke k+5,59						; Set sustain and release
			k=k+7							; Move the pointer to the next voice
1 
		reada,b								; Read a byte of sprite data for the sub and the ship
		poke 2828+3*i,a						; Poke the sub sprite data. The address is some bytes off, since
											; 	the data will move as we initalize more variables
		poke 2889+3*i,b						; Poke the ship sprite data. This data will move just as much.
	next
	dim r,x,t,h,c							; Initalize variables now to make the sprite data move into its
											; 	correct position now rather than when we first fire a torpedo etc
	b=28									; Set how far left the vessels can go
	data 8,16,8,16,190						; Sprite data part 1
2 
	e=249									; Set how far right the vessels can go
	v=53248									; Base address of the VIC-II chip
	poke v+32,6								; Set the screen border to blue
	poke v+33,6								; Set the background to blue
	print "{white}{clr}"spc(30)"<"			; Clear the screen, filling the colour memory with white, so we
											;	can later poke torpedoes onto the screen without setting their
											;	colour. Also print a marker for how far the vessels go.
	s=4										; The inital speed and direction of the sub (+4 pixels/tick)
	p=24									; The inital position of the sub (24 = next to left border)
	t=-1									; t = -1 means the sub is ready to fire a torpedo
	u=2										; u is normally an address in screen memory, but at game start 
											; 	it can point to any address where it's safe to poke a value.
											;	2 is a good choice since address 2 is unused and it's short. 
	i=94									; The initial position of the ship
3 
	poke 2040,45							; Set the sub sprite to address 2880 (2880 / 64 = 45)
	poke 2041,46							; Set the ship sprite to address 2944 (2944 / 64 = 46)
	poke v+29,3								; Set both sprites to be X-expanded
	poke v+39,7								; Sub is yellow
	poke v+40,14							; Ship is light blue
	poke v+21,3								; Turn on both sprites
	d=6										; Ship speed: 6 pixels to the right each tick
	c=9										; Torpedo count
4 
	poke v+1,229							; Set Y position of sub
	poke v+3,58								; Set Y position of ship
	poke k+2,15								; Set SID sound volume to max
	for l=t to .							; We run a loop from -1 to 0 (deciding at the end of the
											; 	loop whether to go back to -1 or allow the loop to end
											; 	- loop ends when the last torpedo has reached the top
											;	of the screen and possibly hit the ship)
		p=p+s								; Change sub position
		poke v,p							; Set the sub sprite X position
		if p>e or p<b then					; Have we passed the critical values where we need to turn around?
			s=-s							; Reverse the direction of the sub
5
		print "{home}tp:"c"pw:"y%"sc:"r		; Print the number of torpedoes left, the power of the currently
											; 	loaded torpedo and the score
		i=i+d								; Change ship position
		poke v+2,i							; Set the ship sub X position
		d=d+12*(i>e)-12*(i<b)				; If the ship is outside the allowed values, reverse the direction
		get a$								; Get a keypress from the keyboard (or an empty string) 			
		a=a$>""								; Set a to -1 if a key was pressed, or 0 if not
6 
		if a and t then						; If a key was pressed and the sub is ready to fire a torpedo:
			t=0								; A torpedo is now under way, and the sub can not fire a torpedo
			u=(p-20)/8+1984					; Calulate the initial torpedo position (a character position in
											;	screen memory) from the sub position in pixels from the
											; 	the leftmost sprite position (which is beneath the left border).
			x=1984-40*y%					; Calculate how far up the screen the torpedo will go before
											; 	slowing down
			y%=rnd(1)*10					; Randomize the power of the next torpedo
			c=c-1							; Decrease the number of torpedoes left
			poke k-4,129					; Start the sound effect for firing a torpedo
7 
		poke k-4,128						; Stop the sound effect for firing a torpedo. If no torpedo was
											;	fired, this has no effect.
		if t=0 then							; If a torpedo is currently under way:
			poke u,32						; Clear the screen address where the torpedo is
			u=u-40+40*(u>x)					; Calculate where address the torpedo should appear next (1 or 2
											; 	lines higher up)
			data48,255,55,255,254,190,252	; Sprite data part 2 (It doesn't matter that this comes after an
											;	IF statement)
8 
		if t=0 then							; If a torpedo is under way:
			t=u<1144						; Change the status to "no torpedo under way" if the new torpedo
											; 	position is on line 1-3 in screen memory
			if peek(v+31)=2 and t then		; If we detect a collision between the ship sprite and a character
											;	and we have just decided that the torpedo has come as far up
											;	on the screen as it should:
				r=r+100						; Increase the score
				poke k-14,5					; Set the frequency for the sound effect for the ship being hit
											; 	(Logically, this belongs in the initalization section on 
											;	line 0-4, but we ran out of space there)
				poke k-11,129				; Start the sound effect for the ship being hit
9 
		poke k-11,128						; Stop the sound effect for the ship being hit, if any
		poke u,32 - 61 * not t				; Poke the torpedo character (93) into the address in screen 
											;	memory where the torpedo is. If there is no torpedo, poke a
											; 	space instead. Poking a space serves no purpose, but it means
											;	we don't have to use IF, and so we can use the rest of their
											; 	line for other purposes.
		l=(c>. or t=.)						; Decide if the main game loop should continue: Continue if we
											; 	still have spare torpedos or a torpedo is currently under way.
	next									; End of the main game loop
	poke v+21,.								; Turn off all sprites.
	print"{clr}score:"r						; Clear the screen and print the score (if the player hit a ship
											; 	with the very last torpedo, the score on the main game screen
											;	is not updated, so we clear the screen and print the correct
											;	score instead.
											
